﻿#region - 版 本 注 释 -
/*----------------------------------------------------------------
 * 版权所有 (c) 2025   保留所有权利。
 * CLR版本：4.0.30319.42000
 * 机器名称：DESKTOP-GLJ2Q8J
 * 公司名称：
 * 命名空间：AutoCAD.EntityTools
 * 唯一标识：1ef392ce-4fbc-4c68-bb2f-a9416cc2aceb
 * 文件名：LineTools
 * 当前用户域：DESKTOP-GLJ2Q8J
 * 
 * 创建者：Guoweihao-79991
 * 电子邮箱：799919859@qq.com
 * 创建时间：2025/5/23 16:28:20
 * 版本：V1.0.0
 *
 * 功能描述(Description):
 * 参考文档(Reference):
 * 数据表(Tables):
 * 作者(Author):Guo
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion - 版 本 注 释 -
namespace AutoCAD.EntityTools
{
    /// <summary>
    /// 多段线工具类
    /// </summary>
    public static class PolylineTools
    {



        #region  创建

        /// <summary>
        /// 多段线创建选项
        /// </summary>
        public class PolylineOptions
        {
            public bool IsClosed { get; set; } = false;
            public double GlobalWidth { get; set; } = 0;
            public double StartWidth { get; set; } = 0;
            public double EndWidth { get; set; } = 0;
            public string Layer { get; set; } = "0";
            public short ColorIndex { get; set; } = 256; // ByLayer
        }


        /// <summary>
        /// 根据点集创建多段线
        /// </summary>
        /// <typeparam name="T">点集合的类型，必须实现 IEnumerable<Point3d> 接口</typeparam>
        /// <param name="points">点集合，用于定义多段线的顶点位置</param>
        /// <param name="db">AutoCAD 数据库对象，用于确定多段线所属的数据库上下文</param>
        /// <param name="options">多段线创建选项，包含线宽、颜色、图层等属性设置，可选参数</param>
        /// <param name="customAction">自定义操作委托，可在多段线创建后执行额外操作，可选参数</param>
        /// <returns>创建的多段线对象</returns>
        /// <exception cref="ArgumentNullException">当 points 或 db 参数为 null 时抛出</exception>
        /// <exception cref="ArgumentException">当 points 集合为空或包含不足2个点时抛出</exception>
        /// <remarks>
        /// 此方法为 IEnumerable<Point3d> 提供扩展方法，简化多段线创建流程。
        /// 支持通过 options 参数统一设置多段线属性，通过 customAction 参数执行自定义逻辑。
        /// 创建的多段线会自动添加到指定数据库的当前空间中。
        /// </remarks>
        public static Polyline CreatePolyline(this IEnumerable<Point3d> points, Database db , 
           PolylineOptions options = null,
           Action<Polyline> customAction = null)
        {
            if (points == null)
                throw new ArgumentNullException(nameof(points));

            var pointList = points.ToList();
            if (pointList.Count < 2)
                throw new ArgumentException("创建多段线至少需要2个点", nameof(points));

            if (options == null)
            {
                options = new PolylineOptions();
            }

            Polyline pl = new Polyline();
            pl.SetDatabaseDefaults();

            // 添加顶点
            for (int i = 0; i < pointList.Count; i++)
            {
                Point3d pt = pointList[i];
                double bulge = 0; // 无圆弧
                double startWidth = options.StartWidth;
                double endWidth = options.EndWidth;

                pl.AddVertexAt(i, pt.ToPoint2d(), bulge, startWidth, endWidth);
            }

            // 设置属性
            pl.Closed = options.IsClosed && pointList.Count > 2;
            pl.ConstantWidth = options.GlobalWidth;
            // 确保图层存在后再设置
            pl.Layer = EnsureLayerExists(db, options.Layer);
            pl.ColorIndex = options.ColorIndex;

            // 自定义操作
            customAction?.Invoke(pl);

            return pl;
        }
        /// <summary>
        /// 判断多段线是否为矩形（优化版）
        /// </summary>
        public static bool IsRectanglePolyline(this Polyline pl)
        {
            if (pl.NumberOfVertices != 4 || !pl.Closed)
                return false;

            // 检查顶点是否共面（3D空间）
            Point3d[] pts = new Point3d[4];
            for (int i = 0; i < 4; i++) pts[i] = pl.GetPoint3dAt(i);

            Vector3d v1 = pts[1] - pts[0];
            Vector3d v2 = pts[2] - pts[0];
            Vector3d normal = v1.CrossProduct(v2);
            double distance = normal.DotProduct(pts[3] - pts[0]);
            if (!distance.IsZero(0.001)) return false;

            // 检查边角是否垂直
            Vector3d[] vectors = new Vector3d[4];
            for (int i = 0; i < 4; i++) vectors[i] = pts[(i + 1) % 4] - pts[i];

            for (int i = 0; i < 4; i++)
            {
                double dot = vectors[i].GetNormal().DotProduct(vectors[(i + 1) % 4].GetNormal());
                if (!dot.IsZero(0.01)) return false;
            }

            return true;
        }
        /// <summary>
        /// 确保图层存在，如果不存在则创建它
        /// </summary>
        /// <param name="db">图形数据库</param>
        /// <param name="layerName">图层名称</param>
        /// <returns>存在的图层名称</returns>
        private static string EnsureLayerExists(Database db, string layerName)
        {
            // 如果图层名为空或者null，使用默认图层"0"
            if (string.IsNullOrEmpty(layerName))
                return "0";

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                LayerTable layerTable = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);

                // 检查图层是否存在
                if (!layerTable.Has(layerName))
                {
                    // 以写模式打开图层表
                    layerTable.UpgradeOpen();

                    // 创建新图层
                    LayerTableRecord layerRecord = new LayerTableRecord();
                    layerRecord.Name = layerName;

                    // 将新图层添加到图层表
                    layerTable.Add(layerRecord);
                    tr.AddNewlyCreatedDBObject(layerRecord, true);
                }

                tr.Commit();
            }

            return layerName;
        }

        /// <summary>
        /// 简化调用：快速创建多段线
        /// </summary>
        public static Polyline CreatePolylineSimple(this IEnumerable<Point3d> points, Database db , Action<Polyline> action = null)
        {
            return points.CreatePolyline(db , null,  action);
        }




        /*
         * 
         * 下一章  队长 ， 别开枪   ， 第二天一早  ， 家里已经做好了丰盛的早饭  ， 郭伟也帮老妈忙活  ， 一楼餐厅 ， 地下室餐厅  ， 大家坐下来吃饭 ， 邱队长表示 ， 他昨天和上级汇报了情况 ， 上级指示是看看能不能这支幸存下来的部队 ， 能否借助郭伟基地，继续救援周边幸存者  ， 看看郭伟什么意思 ， 郭伟表示能为龙国出一份力是自己的义务 ， 马一也表示愿意听从官方指示  ， 收拾好装备 ， 郭伟也把仓库装备提前放了很多在基地仓库里 ，          * 
         */














        /// <summary>
        /// 设置多段线颜色
        /// </summary>
        public static Polyline SetColor(this Polyline polyline, short colorIndex)
        {
            if (polyline != null)
            {
                polyline.ColorIndex = colorIndex;
            }
            return polyline;
        }

        /// <summary>
        /// 设置多段线图层
        /// </summary>
        /// <summary>
        /// 设置多段线图层（确保图层存在）
        /// </summary>
        public static Polyline SetLayer(this Polyline polyline, Database db , string layerName)
        {
            if (polyline == null || string.IsNullOrEmpty(layerName))
                return polyline;

            // 确保图层存在
            string safeLayerName = EnsureLayerExists(db, layerName);

            // 现在可以安全设置图层
            polyline.Layer = safeLayerName;

            return polyline;
        }

        ///// <summary>
        ///// 确保图层存在，如果不存在则创建它
        ///// </summary>
        //private static string EnsureLayerExists(Database db, string layerName)
        //{
        //    // 使用事务操作数据库
        //    using (Transaction tr = db.TransactionManager.StartTransaction())
        //    {
        //        // 打开图层表用于读取
        //        LayerTable layerTable = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);

        //        // 检查图层是否存在
        //        if (!layerTable.Has(layerName))
        //        {
        //            // 图层不存在，创建新图层
        //            layerTable.UpgradeOpen(); // 切换为写模式

        //            LayerTableRecord layerRecord = new LayerTableRecord();
        //            layerRecord.Name = layerName;

        //            // 将新图层添加到图层表
        //            layerTable.Add(layerRecord);
        //            tr.AddNewlyCreatedDBObject(layerRecord, true);
        //        }

        //        tr.Commit();
        //    }

        //    return layerName;
        //}




        #endregion


        #region 宽度


        /// <summary>
        /// 多段线宽度设置选项
        /// </summary>
        public class PolylineWidthOptions
        {
            public double GlobalWidth { get; set; } = 0.0;
            public double StartWidth { get; set; } = 0.0;
            public double EndWidth { get; set; } = 0.0;
            public bool SetVertexWidths { get; set; } = false;
        }

        /// <summary>
        /// 设置多段线宽度（完整版）
        /// </summary>
        /// <param name="polyline">多段线</param>
        /// <param name="options">GlobalWidth 、 StartWidth 、 EndWidth 、SetVertexWidths</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="InvalidOperationException"></exception>
        public static Polyline SetWidth(this Polyline polyline, PolylineWidthOptions options)
        {
            if (polyline == null)
                throw new ArgumentNullException(nameof(polyline));

            if (options == null)
                throw new ArgumentNullException(nameof(options));

            using (Transaction trans = polyline.Database.TransactionManager.StartTransaction())
            {
                try
                {
                    Polyline polylineForWrite = trans.GetObject(polyline.ObjectId, OpenMode.ForWrite) as Polyline;

                    if (polylineForWrite != null)
                    {
                        // 设置全局宽度
                        if (options.GlobalWidth >= 0)
                        {
                            polylineForWrite.ConstantWidth = options.GlobalWidth;
                        }

                        // 设置起始和结束宽度
                        if (options.StartWidth >= 0)
                        {
                            polylineForWrite.SetStartWidthAt(0, options.StartWidth);
                        }

                        if (options.EndWidth >= 0 && polylineForWrite.NumberOfVertices > 0)
                        {
                            polylineForWrite.SetEndWidthAt(polylineForWrite.NumberOfVertices - 1, options.EndWidth);
                        }

                        // 设置所有顶点的宽度
                        if (options.SetVertexWidths)
                        {
                            for (int i = 0; i < polylineForWrite.NumberOfVertices; i++)
                            {
                                if (options.StartWidth >= 0)
                                    polylineForWrite.SetStartWidthAt(i, options.StartWidth);
                                if (options.EndWidth >= 0)
                                    polylineForWrite.SetEndWidthAt(i, options.EndWidth);
                            }
                        }
                    }

                    trans.Commit();
                }
                catch (Exception ex)
                {
                    trans.Abort();
                    throw new InvalidOperationException($"设置多段线宽度失败: {ex.Message}", ex);
                }
            }

            return polyline;
        }

        /// <summary>
        /// 设置多段线全局宽度（简化版）
        /// </summary>
        /// <param name="polyline">多段线</param>
        /// <param name="width">宽度</param>
        /// <returns>返回多段线</returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentException"></exception>
        public static Polyline SetConstantWidth(this Polyline polyline, double width)
        {
            if (polyline == null)
                throw new ArgumentNullException(nameof(polyline));

            if (width < 0)
                throw new ArgumentException("宽度不能为负数", nameof(width));

            using (Transaction trans = polyline.Database.TransactionManager.StartTransaction())
            {
                Polyline polylineForWrite = trans.GetObject(polyline.ObjectId, OpenMode.ForWrite) as Polyline;

                if (polylineForWrite != null)
                {
                    polylineForWrite.ConstantWidth = width;
                }

                trans.Commit();
            }

            return polyline;
        }

        /// <summary>
        /// 设置多段线顶点宽度
        /// </summary>
        /// <param name="polyline">多段线</param>
        /// <param name="vertexIndex">顶点索引</param>
        /// <param name="startWidth">开端宽度</param>
        /// <param name="endWidth">结束宽度</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <exception cref="ArgumentException"></exception>
        public static Polyline SetVertexWidth(this Polyline polyline, int vertexIndex, 
            double startWidth, double endWidth)
        {
            if (polyline == null)
                throw new ArgumentNullException(nameof(polyline));

            if (vertexIndex < 0 || vertexIndex >= polyline.NumberOfVertices)
                throw new ArgumentOutOfRangeException(nameof(vertexIndex));

            if (startWidth < 0 || endWidth < 0)
                throw new ArgumentException("宽度不能为负数");

            using (Transaction trans = polyline.Database.TransactionManager.StartTransaction())
            {
                Polyline polylineForWrite = trans.GetObject(polyline.ObjectId, OpenMode.ForWrite) as Polyline;

                if (polylineForWrite != null)
                {
                    polylineForWrite.SetStartWidthAt(vertexIndex, startWidth);
                    polylineForWrite.SetEndWidthAt(vertexIndex, endWidth);
                }

                trans.Commit();
            }

            return polyline;
        }


        /// <summary>
        /// 安全设置多段线宽度（不抛出异常）
        /// </summary>
        /// <param name="polyline">多段线</param>
        /// <param name="width">宽度</param>
        /// <param name="errorMessage">异常信息</param>
        /// <returns></returns>
        public static bool TrySetWidth(this Polyline polyline, double width, out string errorMessage)
        {
            errorMessage = null;

            if (polyline == null)
            {
                errorMessage = "多段线对象不能为空";
                return false;
            }

            if (width < 0)
            {
                errorMessage = "宽度不能为负数";
                return false;
            }

            try
            {
                using (Transaction trans = polyline.Database.TransactionManager.StartTransaction())
                {
                    Polyline polylineForWrite = trans.GetObject(polyline.ObjectId, OpenMode.ForWrite) as Polyline;

                    if (polylineForWrite == null)
                    {
                        errorMessage = "无法以写模式打开多段线";
                        trans.Abort();
                        return false;
                    }

                    polylineForWrite.ConstantWidth = width;
                    trans.Commit();
                    return true;
                }
            }
            catch (Exception ex)
            {
                errorMessage = ex.Message;
                return false;
            }
        }

        /// <summary>
        /// 批量设置多段线宽度
        /// </summary>
        /// <param name="polylines">多段线集合</param>
        /// <param name="width">宽度</param>
        public static void SetWidths(this IEnumerable<Polyline> polylines, double width)
        {
            if (polylines == null)
                return;

            // 按数据库分组处理
            var groupedByDatabase = polylines.GroupBy(p => p.Database);

            foreach (var group in groupedByDatabase)
            {
                if (group.Key == null || !group.Any())
                    continue;

                using (Transaction trans = group.Key.TransactionManager.StartTransaction())
                {
                    foreach (var polyline in group)
                    {
                        try
                        {
                            Polyline polylineForWrite = trans.GetObject(polyline.ObjectId, OpenMode.ForWrite) as Polyline;
                            if (polylineForWrite != null)
                            {
                                polylineForWrite.ConstantWidth = width;
                            }
                        }
                        catch
                        {
                            // 忽略单个多段线的错误，继续处理其他多段线
                            continue;
                        }
                    }

                    trans.Commit();
                }
            }
        }

        #endregion


        #region 选择集

        /// <summary>
        /// 手选多段线
        /// </summary>
        /// <param name="ed">Editor</param>
        /// <param name="prompt">提示信息</param>
        /// <returns></returns>
        public static Polyline SelectPolyline(this Editor ed , string prompt = "\n请选择多段线: ")
        {
            if(ed == null) return new Polyline();
            PromptEntityOptions options = new PromptEntityOptions(prompt);
            var polyline = new Polyline();
            options.SetRejectMessage(prompt);
            options.AddAllowedClass(typeof(Polyline), true);    
            PromptEntityResult result = ed.GetEntity(options);
            if (result.Status == PromptStatus.OK)
            {
                $"{result.ObjectId}".CadMessage2();
                polyline = ed.GetEntity<Polyline>(result.ObjectId);
                return polyline;
            }
            else
                $"选择取消".CadMessage2();
            return polyline;
        }



        /// <summary>
        /// 判断多段线是否为矩形
        /// </summary>
        public static bool IsRectangle(this Polyline pl)
        {
            if (pl.NumberOfVertices != 4)
                return false;

            // 获取所有顶点
            Point2d[] pts = new Point2d[4];
            for (int i = 0; i < 4; i++)
            {
                pts[i] = pl.GetPoint2dAt(i);
            }

            // 计算四条边的向量
            Vector2d[] vectors = new Vector2d[4];
            for (int i = 0; i < 4; i++)
            {
                vectors[i] = pts[(i + 1) % 4] - pts[i];
            }

            // 检查相邻边是否垂直（点积为0）
            for (int i = 0; i < 4; i++)
            {
                double dot = vectors[i].GetNormal().DotProduct(vectors[(i + 1) % 4].GetNormal());
                if (!dot.IsZero(0.01)) // 允许微小误差
                    return false;
            }

            return true;
        }


        /// <summary>
        /// 选择多个多段线（带关键词支持）
        /// </summary>
        public static List<Polyline> SelectPolylinesWithKeywords(this Editor ed, string prompt = "\n请选择多段线[窗口(W)/交叉(C)]: ")
        {
            var polylines = new List<Polyline>();

            if (ed == null) return polylines;

            try
            {
                PromptSelectionOptions options = new PromptSelectionOptions();
                options.MessageForAdding = prompt;
                options.SingleOnly = false;
                options.AllowDuplicates = false;

                // 设置关键词
                options.Keywords.Add("W", "窗口选择");
                options.Keywords.Add("C", "交叉选择");

                // 关键词输入事件处理
                options.KeywordInput += (sender, e) =>
                {
                    switch (e.Input.ToUpper())
                    {
                        case "W":
                            // 窗口选择 - AutoCAD会自动处理
                            break;
                        case "C":
                            // 交叉选择 - AutoCAD会自动处理
                            break;
                    }
                };

                SelectionFilter filter = new SelectionFilter(new[]
                {
            new TypedValue(0, "LWPOLYLINE,POLYLINE")
        });

                PromptSelectionResult result = ed.GetSelection(options, filter);

                if (result.Status == PromptStatus.OK)
                {
                    polylines = GetPolylinesFromSelection(ed, result.Value);
                    $"成功选择了 {polylines.Count} 个多段线".CadMessage2();
                }
                else if (result.Status == PromptStatus.Keyword)
                {
                    // 用户输入了关键词
                    $"用户选择了关键词: {result.Value}".CadMessage2();
                }
                else
                {
                    $"选择取消".CadMessage2();
                }
            }
            catch (Exception ex)
            {
                $"选择多段线时出错: {ex.Message}".CadMessage2();
            }

            return polylines;
        }

        /// <summary>
        /// 选择多个多段线（主要方法）
        /// </summary>
        public static List<Polyline> SelectPolylines(this Editor ed, string prompt = "\n请选择多段线: ")
        {
            var polylines = new List<Polyline>();

            if (ed == null) return polylines;

            try
            {
                PromptSelectionOptions options = new PromptSelectionOptions();
                options.MessageForAdding = prompt;
                options.SingleOnly = false;
                options.AllowDuplicates = false;

                // 选择过滤器：只选择多段线
                SelectionFilter filter = new SelectionFilter(new[]
                {
                new TypedValue(0, "LWPOLYLINE,POLYLINE")
            });

                PromptSelectionResult result = ed.GetSelection(options, filter);

                if (result.Status == PromptStatus.OK)
                {
                    polylines = GetPolylinesFromSelection(ed, result.Value);
                    $"成功选择了 {polylines.Count} 个多段线".CadMessage2();
                }
                else
                {
                    $"选择取消".CadMessage2();
                }
            }
            catch (Exception ex)
            {
                $"选择多段线时出错: {ex.Message}".CadMessage2();
            }

            return polylines;
        }

        /// <summary>
        /// 从选择集中提取多段线
        /// </summary>
        private static List<Polyline> GetPolylinesFromSelection(Editor ed, SelectionSet selection)
        {
            var polylines = new List<Polyline>();

            if (selection == null) return polylines;

            try
            {
                using (var tr = ed.Document.TransactionManager.StartTransaction())
                {
                    foreach (SelectedObject selectedObject in selection)
                    {
                        if (selectedObject != null)
                        {
                            var entity = tr.GetObject(selectedObject.ObjectId, OpenMode.ForRead) as Entity;
                            if (entity is Polyline polyline)
                            {
                                polylines.Add(polyline);
                            }
                        }
                    }
                    tr.Commit();
                }
            }
            catch (Exception ex)
            {
                $"提取多段线时出错: {ex.Message}".CadMessage2();
            }

            return polylines;
        }
        #endregion





















        /// <summary>
        /// 计算两个平行多段线之间的距离
        /// </summary>
        /// <param name="pl1"></param>
        /// <param name="pl2"></param>
        /// <returns></returns>
        public static double GetDistanceBetweenParallelPolylines(this Polyline pl1, Polyline pl2)
        {
            try
            {
                if (pl1 == null || pl2 == null) return 0;
                // 验证平行性（可选）  取消验证
                //if (!ArePolylinesParallel(pl1, pl2))
                //    return 0.0;
                //throw new ArgumentException("多段线不平行");

                //方法1：取首段直线计算垂直距离（效率最高）
                LineSegment3d seg1 = pl1.GetLineSegmentAt(0);
                Line3d line1 = new Line3d(seg1.StartPoint, seg1.EndPoint);
                return line1.GetDistanceTo(pl2.GetPoint3dAt(0));

                // 方法2：计算所有对应线段距离取平均值（更精确）

                double totalDistance = 0;
                int count = Math.Min(pl1.NumberOfVertices, pl2.NumberOfVertices);
                for (int i = 0; i < count; i++)
                {
                    LineSegment3d seg = pl1.GetLineSegmentAt(i);
                    Line3d line = new Line3d(seg.StartPoint, seg.EndPoint);
                    totalDistance += line.GetDistanceTo(pl2.GetPoint3dAt(i));
                }
                return totalDistance / count;

            }
            catch (Exception ex)
            {

                (ex.Message).CadMessage2();
                return -1;
            }
        }

        // 平行性验证方法
        private static bool ArePolylinesParallel(Polyline pl1, Polyline pl2)
        {
            try
            {
                if (pl1 == null && pl2 == null)
                {
                    return false;
                }
                Vector3d normal1 = pl1.Normal;
                Vector3d normal2 = pl2.Normal;
                return normal1.IsParallelTo(normal2);
            }
            catch (Exception ex)
            {

                (ex.Message).CadMessage2();
                return false;
            }
        }

        /// <summary>
        /// 多段线属性复制选项
        /// </summary>
        public class PolylineCopyOptions
        {
            public bool CopyGeometry { get; set; } = true;
            public bool CopyWidths { get; set; } = true;
            public bool CopyBulges { get; set; } = true;
            public bool CopyProperties { get; set; } = true;
            public bool CopyAppearance { get; set; } = true;
        }

        /// <summary>
        /// 复制多段线属性（完整版）
        /// </summary>
        /// <summary>
        /// 复制多段线属性（解决几何退化问题）
        /// </summary>
        public static void CopyPolylineProperties(this Polyline source, Polyline target)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            if (target == null)
                throw new ArgumentNullException(nameof(target));

            // 检查源多段线是否有有效的几何数据
            if (source.NumberOfVertices < 2)
                throw new InvalidOperationException("源多段线顶点数量不足");

            using (Transaction trans = target.Database.TransactionManager.StartTransaction())
            {
                try
                {
                    Polyline targetForWrite = trans.GetObject(target.ObjectId, OpenMode.ForWrite) as Polyline;

                    if (targetForWrite != null)
                    {
                        // 清除目标多段线的所有顶点
                        while (targetForWrite.NumberOfVertices > 0)
                        {
                            targetForWrite.RemoveVertexAt(0);
                        }

                        // 复制顶点，确保几何有效性
                        for (int i = 0; i < source.NumberOfVertices; i++)
                        {
                            Point2d point = source.GetPoint2dAt(i);
                            double bulge = source.GetBulgeAt(i);
                            double startWidth = source.GetStartWidthAt(i);
                            double endWidth = source.GetEndWidthAt(i);

                            // 验证顶点有效性
                            if (!IsValidPoint(point))
                                continue;

                            targetForWrite.AddVertexAt(i, point, bulge, startWidth, endWidth);
                        }

                        // 验证目标多段线是否有足够的顶点
                        if (targetForWrite.NumberOfVertices < 2)
                            throw new InvalidOperationException("复制后目标多段线顶点数量不足");

                        // 复制其他属性
                        CopyNonGeometricProperties(source, targetForWrite);
                    }

                    trans.Commit();
                }
                catch (Exception ex)
                {
                    trans.Abort();
                    throw new InvalidOperationException($"复制多段线属性失败: {ex.Message}", ex);
                }
            }
        }

        /// <summary>
        /// 复制非几何属性
        /// </summary>
        private static void CopyNonGeometricProperties(Polyline source, Polyline target)
        {
            target.Closed = source.Closed;
            target.Elevation = source.Elevation;

            // 只有当法向量有效时才复制
            if (!source.Normal.IsZeroLength() && source.Normal.Length > 1e-10)
            {
                target.Normal = source.Normal;
            }

            target.ConstantWidth = source.ConstantWidth;
            target.LayerId = source.LayerId;
            target.ColorIndex = source.ColorIndex;

            // 可选：复制其他属性
            try
            {
                target.LinetypeId = source.LinetypeId;
                target.LineWeight = source.LineWeight;
                target.LinetypeScale = source.LinetypeScale;
            }
            catch
            {
                // 忽略可选的属性复制错误
            }
        }

        /// <summary>
        /// 检查点是否有效（避免退化几何）
        /// </summary>
        private static bool IsValidPoint(Point2d point)
        {
            // 检查点坐标是否为有效数值
            return !double.IsNaN(point.X) && !double.IsNaN(point.Y) &&
                   !double.IsInfinity(point.X) && !double.IsInfinity(point.Y);
        }

        /// <summary>
        /// 检查多段线几何有效性
        /// </summary>
        private static bool IsPolylineGeometryValid(Polyline pline)
        {
            if (pline.NumberOfVertices < 2)
                return false;

            // 检查所有顶点是否有效
            for (int i = 0; i < pline.NumberOfVertices; i++)
            {
                Point2d point = pline.GetPoint2dAt(i);
                if (!IsValidPoint(point))
                    return false;
            }

            // 检查是否有重复的点（可能导致退化几何）
            for (int i = 0; i < pline.NumberOfVertices - 1; i++)
            {
                Point2d p1 = pline.GetPoint2dAt(i);
                Point2d p2 = pline.GetPoint2dAt(i + 1);

                if (p1.GetDistanceTo(p2) < 1e-10) // 距离太近，可能是重复点
                    return false;
            }

            return true;
        }
        /// <summary>
        /// 安全复制多段线属性（不抛出异常）
        /// </summary>
        public static bool TryCopyPolylineProperties(this Polyline source, Polyline target, out string errorMessage)
        {
            errorMessage = null;

            if (source == null)
            {
                errorMessage = "源多段线不能为空";
                return false;
            }

            if (target == null)
            {
                errorMessage = "目标多段线不能为空";
                return false;
            }

            try
            {
                using (Transaction trans = target.Database.TransactionManager.StartTransaction())
                {
                    Polyline targetForWrite = trans.GetObject(target.ObjectId, OpenMode.ForWrite) as Polyline;

                    if (targetForWrite == null)
                    {
                        errorMessage = "无法以写模式打开目标多段线";
                        trans.Abort();
                        return false;
                    }

                    // 清除目标多段线
                    while (targetForWrite.NumberOfVertices > 0)
                    {
                        targetForWrite.RemoveVertexAt(0);
                    }

                    // 复制属性
                    for (int i = 0; i < source.NumberOfVertices; i++)
                    {
                        targetForWrite.AddVertexAt(i, source.GetPoint2dAt(i), source.GetBulgeAt(i),
                            source.GetStartWidthAt(i), source.GetEndWidthAt(i));
                    }

                    targetForWrite.Closed = source.Closed;
                    targetForWrite.Elevation = source.Elevation;
                    targetForWrite.Normal = source.Normal;
                    targetForWrite.ConstantWidth = source.ConstantWidth;

                    trans.Commit();
                    return true;
                }
            }
            catch (Exception ex)
            {
                errorMessage = ex.Message;
                return false;
            }
        }
        /// <summary>
        /// 创建多段线的完整副本
        /// </summary>
        public static Polyline ClonePolyline(this Polyline source, Database targetDb = null)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            targetDb ??= source.Database;

            Polyline clone = new Polyline();

            using (Transaction trans = targetDb.TransactionManager.StartTransaction())
            {
                try
                {
                    // 复制顶点和几何属性
                    for (int i = 0; i < source.NumberOfVertices; i++)
                    {
                        clone.AddVertexAt(i, source.GetPoint2dAt(i), source.GetBulgeAt(i),
                            source.GetStartWidthAt(i), source.GetEndWidthAt(i));
                    }

                    // 复制其他属性
                    clone.Closed = source.Closed;
                    clone.Elevation = source.Elevation;
                    clone.Normal = source.Normal;
                    clone.ConstantWidth = source.ConstantWidth;
                    clone.LayerId = source.LayerId;
                    clone.Color = source.Color;

                    trans.Commit();
                }
                catch
                {
                    trans.Abort();
                    throw;
                }
            }

            return clone;
        }
        /// <summary>
        /// 隐藏图框内部实体
        /// </summary>
        /// <param name="frame"></param>
        /// <param name="tr"></param>
        /// <param name="btr"></param>
        public static void VisibleEntitiesInsideFrame(this Polyline frame, Transaction tr,
            BlockTableRecord btr, bool isVisible = false)
        {
            // 获取多段线的边界
            Extents3d frameExtents = frame.Bounds.Value;

            // 遍历块表中的实体
            foreach (ObjectId id in btr)
            {
                Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
                if (ent == null || ent == frame || !ent.Bounds.HasValue) continue;

                // 快速检查：实体是否在图框的边界范围内
                if (!ContainsExtents(frameExtents, ent.Bounds.Value))
                    continue;

                // 精确检查：实体是否在图框内部
                if (IsEntityInsidePolyline(ent, frame))
                {
                    // 打开实体以修改
                    ent.UpgradeOpen();
                    //ent.Visible = false; // 或者使用 ent.IsOff = true;
                    ent.Visible = isVisible; // 或者使用 ent.IsOff = true;
                }
            }
        }
        /// <summary>
        /// 检查一个边界框是否完全包含另一个边界框
        /// </summary>
        /// <param name="outer">外部边界框</param>
        /// <param name="inner">内部边界框</param>
        /// <returns>是否包含</returns>
        public static bool ContainsExtents(Extents3d outer, Extents3d inner)
        {
            return outer.MinPoint.X <= inner.MinPoint.X &&
                   outer.MinPoint.Y <= inner.MinPoint.Y &&
                   outer.MinPoint.Z <= inner.MinPoint.Z &&
                   outer.MaxPoint.X >= inner.MaxPoint.X &&
                   outer.MaxPoint.Y >= inner.MaxPoint.Y &&
                   outer.MaxPoint.Z >= inner.MaxPoint.Z;
        }

        /// <summary>
        /// 检查实体是否在多段线内部
        /// </summary>
        /// <param name="ent">要检查的实体</param>
        /// <param name="pl">多段线图框</param>
        /// <returns>是否在多段线内部</returns>
        public static bool IsEntityInsidePolyline(Entity ent, Polyline pl)
        {
            // 这里简化处理，实际应用中可能需要更精确的检测
            // 对于精确检测，可以使用射线法或AutoCAD的API

            // 获取实体的中心点（简化处理）
            Extents3d entExtents = ent.Bounds.Value;
            Point3d center = new Point3d(
                (entExtents.MinPoint.X + entExtents.MaxPoint.X) / 2,
                (entExtents.MinPoint.Y + entExtents.MaxPoint.Y) / 2,
                0);

            // 检查中心点是否在多段线内
            return IsPointInsidePolyline(center, pl);
        }


        /// <summary>
        /// 使用射线法检查点是否在多段线内部
        /// </summary>
        /// <param name="point">要检查的点</param>
        /// <param name="pl">多段线</param>
        /// <returns>点是否在多段线内部</returns>
        public static bool IsPointInsidePolyline(Point3d point, Polyline pl)
        {
            // 实现射线法
            int intersections = 0;
            int vertexCount = pl.NumberOfVertices;
            Point2d testPoint = new Point2d(point.X, point.Y);

            for (int i = 0; i < vertexCount; i++)
            {
                Point2d p1 = pl.GetPoint2dAt(i);
                Point2d p2 = pl.GetPoint2dAt((i + 1) % vertexCount);

                if (RayCrossesSegment(testPoint, p1, p2))
                {
                    intersections++;
                }
            }

            return (intersections % 2) == 1;
        }

        /// <summary>
        /// 判断两个向量是否平行
        /// </summary>
        /// <param name="point"></param>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        private static bool RayCrossesSegment(Point2d point, Point2d a, Point2d b)
        {
            // 简化版的射线与线段交叉检测
            if ((a.Y > point.Y) == (b.Y > point.Y))
                return false;

            double x = (b.X - a.X) * (point.Y - a.Y) / (b.Y - a.Y) + a.X;
            return x > point.X;
        }
        /// <summary>
        /// 创建中心线
        /// </summary>
        /// <param name="pline1"></param>
        /// <param name="pline2"></param>
        /// <param name="distanceTolerance"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static List<Curve> CreateCenterLineByExploding(this Polyline pline1, Polyline pline2, double distanceTolerance)
        {
            // 验证输入
            if (pline1 == null || pline2 == null)
                throw new ArgumentNullException("输入多段线不能为null");

            // 解组多段线为单独的线段
            var segments1 = ExplodePolyline(pline1);
            var segments2 = ExplodePolyline(pline2);
            var finds = new List<Curve>();
            // 创建结果多段线
            Polyline centerPline = new Polyline();
            centerPline.SetDatabaseDefaults();
            CopyProperties(pline1, centerPline);

            // 处理每对线段
            for (int i = 0; i < segments1.Count; i++)
            {
                Curve seg1 = segments1[i];
                Curve seg2 = segments2[i];

                // 根据线段类型处理
                if (seg1 is Line line1 && seg2 is Line line2)
                {
                    ProcessLinePair((Line)seg1, (Line)seg2, centerPline, i == 0, distanceTolerance);
                    var line = CalculateLineCenterLine(line1, line2, distanceTolerance);
                    finds.Add(line);
                }
                else if (seg1 is Arc arc1 && seg2 is Arc arc2)
                {
                    //ProcessArcPair2((Arc)seg1, (Arc)seg2, centerPline, i == 0);
                    var centerarc = (CalculateArcCenterLine(arc1, arc2));
                    finds.Add(centerarc);
                }
                else
                {
                    break;
                    //throw new ArgumentException($"线段类型不匹配或不受支持");
                }
            }

            // 清理临时对象
            foreach (var seg in segments1) seg.Dispose();
            foreach (var seg in segments2) seg.Dispose();

            return finds;
        }
        /// <summary>
        /// 计算两条平行圆弧的中线
        /// </summary>

        /// <summary>
        /// 计算两条平行圆弧的中线
        /// </summary>
        private static Arc CalculateArcCenterLine(Arc arc1, Arc arc2)
        {
            // 检查法向量方向
            Vector3d normal1 = arc1.Normal;
            Vector3d normal2 = arc2.Normal;

            if (normal1.DotProduct(normal2) < 0)
                normal2 = -normal2;

            // 计算中点参数
            Point3d center = (arc1.Center.Add(arc2.Center)) / 2;
            double radius = (arc1.Radius + arc2.Radius) / 2;

            // 计算角度范围（取两者的并集）
            double startAngle = Math.Min(arc1.StartAngle, arc2.StartAngle);
            double endAngle = Math.Max(arc1.EndAngle, arc2.EndAngle);




            // 确保角度有效
            if (startAngle > endAngle)
            {
                double temp = startAngle;
                startAngle = endAngle;
                endAngle = temp;
            }
            //采用原有的弧度
            startAngle = arc1.StartAngle;
            endAngle = arc1.EndAngle;
            return new Arc(center, normal1, radius, startAngle, endAngle);
        }



        /// <summary>
        /// 处理直线对
        /// </summary>
        private static void ProcessLinePair(Line line1, Line line2, Polyline centerPline, bool isFirstSegment, double distanceTolerance)
        {
            Point3d midStart = line1.StartPoint.MidPoint(line2.StartPoint);
            Point3d midEnd = line1.StartPoint.MidPoint(line2.EndPoint);

            var line = CalculateLineCenterLine(line1, line2, distanceTolerance);
            if (line != null)
            {

                midStart = line.StartPoint;
                midEnd = line.EndPoint;
            }

            if (isFirstSegment)
            {
                centerPline.AddVertexAt(0, new Point2d(midStart.X, midStart.Y), 0, 0, 0);
            }
            centerPline.AddVertexAt(centerPline.NumberOfVertices, new Point2d(midEnd.X, midEnd.Y), 0, 0, 0);
        }

        /// <summary>
        /// 计算两条平行直线的中线（优化版）
        /// </summary>
        private static Line CalculateLineCenterLine(Line line1, Line line2, double distanceTolerance)
        {
            //测试
            //return line1.GetCenterLine(line2);

            //const double tolerance = 1e-5; // 几何计算容差
            Point3d midStart = new Point3d();
            Point3d midEnd = new Point3d();
            // 1. 验证输入有效性
            if (line1 == null || line2 == null)
                throw new ArgumentNullException("输入直线不能为null");

            var thickness = line1.CalculateShortestDistanceBetweenParallelLines(line2, distanceTolerance);
            var addThickness = thickness / 2;
            //读取配置
            var tolerance = distanceTolerance;
            //var allowThickness = ConfigPath.GetCustomConfig().AllowedDistances;

            //var contains = allowThickness.ContainsThickness(addThickness, tolerance);
            //if (!contains)
            //    return null;


            // 2. 计算方向向量（带归一化处理）
            Vector3d dir1 = (line1.EndPoint - line1.StartPoint).GetNormal();
            Vector3d dir2 = (line2.EndPoint - line2.StartPoint).GetNormal();

            // 3. 确保方向一致（处理反向平行情况）
            if (dir1.DotProduct(dir2) < -0.99) // 近似反平行
            {
                dir2 = -dir2;
            }
            else if (Math.Abs(dir1.DotProduct(dir2)) < 0.99) // 非平行线
            {
                throw new ArgumentException("输入直线必须平行");
            }

            // 4. 计算投影参数（优化算法）
            Point3d[] testPoints = { line1.StartPoint, line1.EndPoint, line2.StartPoint, line2.EndPoint };

            double minT = double.MaxValue;
            double maxT = double.MinValue;
            bool useLine1AsBase = true;

            // 选择较长直线作为基准线
            double len1 = line1.Length;
            double len2 = line2.Length;
            Line baseLine = len1 > len2 ? line1 : line2;
            Line otherLine = len1 > len2 ? line2 : line1;
            Vector3d baseDir = (baseLine.EndPoint - baseLine.StartPoint).GetNormal();

            foreach (var point in testPoints)
            {
                Vector3d vec = point - baseLine.StartPoint;
                double t = vec.DotProduct(baseDir);

                minT = Math.Min(minT, t);
                maxT = Math.Max(maxT, t);
            }

            // 5. 处理特殊情况（如零长度线段）
            if (Math.Abs(maxT - minT) < tolerance)
            {
                // 取两条直线的中点连线  - 逻辑错误
                //Point3d mid1 = (line1.StartPoint.Add(line1.EndPoint)) / 2;
                //Point3d mid2 = (line2.StartPoint.Add(line2.EndPoint)) / 2;


                //return new Line(mid1, mid2);

                midStart = (line1.StartPoint.Add(baseDir * minT).Add(
                  GetProjectionPoint(line2, line1.StartPoint + baseDir * minT))) / 2;

                midEnd = (line1.StartPoint.Add(baseDir * maxT).Add(
                                GetProjectionPoint(line2, line1.StartPoint + baseDir * maxT))) / 2;

                /*
                 * 新增距离检查
                 * 生成墙中线和两根墙线的距离相加
                 * 减去两根线的距离
                 * 相减不小于误差值
                 */
                var resLine1 = new Line(midStart, midEnd);
                var dis1_i = resLine1.CalculateShortestDistanceBetweenParallelLines(line1, distanceTolerance);
                var dis2_i = resLine1.CalculateShortestDistanceBetweenParallelLines(line2, distanceTolerance);
                if (Math.Abs((dis1_i + dis2_i) - thickness) <= distanceTolerance)
                {
                    return resLine1;
                }
                else
                {
                    return null;
                }

                return new Line(midStart, midEnd);
            }



            var points = GetBothSideEndPoints(line1, line2);

            //if (points is null)
            //{
            // 6. 计算中线端点（优化数值稳定性）
            midStart = (baseLine.StartPoint.Add(baseDir * minT).Add(
                              GetProjectionPoint(otherLine, baseLine.StartPoint + baseDir * minT))) / 2;

            midEnd = (baseLine.StartPoint.Add(baseDir * maxT).Add(
                            GetProjectionPoint(otherLine, baseLine.StartPoint + baseDir * maxT))) / 2;
            //}
            //else
            //{
            //    midStart = points.Item1.Item1.GetCenterPointInTwoPointBetween(points.Item1.Item2);
            //    midEnd = points.Item2.Item1.GetCenterPointInTwoPointBetween(points.Item2.Item2);
            //}

            // 7. 验证结果有效性
            if (midStart.DistanceTo(midEnd) < tolerance)
            {
                throw new InvalidOperationException("生成的中线长度过短");
            }

            //检查距离
            var resLine = new Line(midStart, midEnd);
            var dis1 = resLine.CalculateShortestDistanceBetweenParallelLines(line1, distanceTolerance);
            var dis2 = resLine.CalculateShortestDistanceBetweenParallelLines(line2, distanceTolerance);
            if (Math.Abs((dis1 + dis2) - thickness) <= distanceTolerance)
            {
                return resLine;
            }
            else
            {
                return null;
            }
            //return new Line(midStart, midEnd);
        }
        /// <summary>
        /// 获取两条平行直线两侧的端点对
        /// </summary>
        /// <param name="line1">第一条直线</param>
        /// <param name="line2">第二条直线</param>
        /// <param name="tolerance">容差</param>
        /// <returns>
        /// Tuple包含：
        /// Item1: 同一侧的点对(线1的点, 线2的点)
        /// Item2: 另一侧的点对(线1的点, 线2的点)
        /// 如果不平行返回null
        /// </returns>
        public static Tuple<Tuple<Point3d, Point3d>, Tuple<Point3d, Point3d>>
            GetBothSideEndPoints(Line line1, Line line2)
        {
            // 1. 检查平行性
            Vector3d dir1 = line1.StartPoint.GetVectorTo(line1.EndPoint);
            Vector3d dir2 = line2.StartPoint.GetVectorTo(line2.EndPoint); ;

            if (!dir1.IsParallelTo(dir2))
                return null;

            // 2. 计算所有端点组合
            var points1 = new[] { line1.StartPoint, line1.EndPoint };
            var points2 = new[] { line2.StartPoint, line2.EndPoint };

            // 3. 找出最近的两个点对（同一侧）
            Point3d closest1 = points1[0];
            Point3d closest2 = points2.OrderBy(p => p.DistanceTo(closest1)).First();

            // 4. 确定另一侧的点
            Point3d other1 = points1.First(p => !p.IsEqualTo(closest1));
            Point3d other2 = points2.First(p => !p.IsEqualTo(closest2));

            // 5. 验证方向一致性
            Vector3d vec1 = closest2 - closest1;
            Vector3d vec2 = other2 - other1;

            // 如果方向相反，交换另一侧的点
            if (!vec1.IsParallelTo(vec2))
            {
                other2 = points2.First(p => p.IsEqualTo(closest2));
            }

            return Tuple.Create(
                Tuple.Create(closest1, closest2),
                Tuple.Create(other1, other2)
            );
        }
        /// <summary>
        /// 获取点在直线上的投影点
        /// </summary>
        private static Point3d GetProjectionPoint(Line line, Point3d point)
        {
            Vector3d vec = line.EndPoint - line.StartPoint;
            Vector3d pointVec = point - line.StartPoint;
            double t = pointVec.DotProduct(vec) / vec.LengthSqrd;
            return line.StartPoint + vec * t;
        }

        private static List<Curve> ExplodePolyline(Polyline pline)
        {
            var segments = new List<Curve>();
            for (int i = 0; i < pline.NumberOfVertices; i++)
            {
                SegmentType segType = pline.GetSegmentType(i);
                switch (segType)
                {
                    case SegmentType.Line:
                        LineSegment2d lineSeg = pline.GetLineSegment2dAt(i);
                        segments.Add(new Line(lineSeg.StartPoint.Point2dToPoint3d(), lineSeg.EndPoint.Point2dToPoint3d()));
                        break;

                    case SegmentType.Arc:
                        double bulge = pline.GetBulgeAt(i);
                        CircularArc2d arcSeg = pline.GetArcSegment2dAt(i);

                        // 根据凸度正负调整方向
                        Vector3d normal = pline.Normal; // 继承多段线的法向量
                        if (!(bulge < 0)) // 顺时针方向
                        {
                            // 反转起点/终点并保持法向量一致
                            segments.Add(new Arc(
                                arcSeg.Center.Point2dToPoint3d(),
                                normal,
                                arcSeg.Radius,
                                Math.PI - arcSeg.EndAngle,
                                Math.PI - arcSeg.StartAngle
                                ));
                        }
                        else // 逆时针方向（默认）
                        {
                            segments.Add(new Arc(
                                arcSeg.Center.Point2dToPoint3d(),
                                normal,
                                arcSeg.Radius,
                                arcSeg.StartAngle,
                                arcSeg.EndAngle
                                ));
                        }
                        break;
                }
            }
            return segments;
        }
        /// <summary>
        /// 复制属性
        /// </summary>
        private static void CopyProperties(Polyline source, Polyline target)
        {
            target.Layer = source.Layer;
            target.Color = source.Color;
            target.Linetype = source.Linetype;
            target.LineWeight = source.LineWeight;
            target.Closed = source.Closed;
        }

    }
}
